package com.example.demo.utils.http;


//import com.alibaba.fastjson.JSON;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;
/**
 * http 组件工具类
 *
 * @author steel
 * @date 2019/2/20
 * @version  1.0.0
 *
 */
public class HttpClientUtil {

    public static final int CONNECTION_TIMEOUT_MS = 360000;

    public static final int SO_TIMEOUT_MS = 360000;

    public static final String CONTENT_TYPE_JSON_CHARSET = "application/json;charset=gbk";

    public static final String CONTENT_TYPE_XML_CHARSET = "application/xml;charset=gbk";

    /**
     * httpclient读取内容时使用的字符集
     */
    public static final String CONTENT_CHARSET = "GBK";

    public static final Charset UTF_8 = Charset.forName("UTF-8");

    public static final Charset GBK = Charset.forName(CONTENT_CHARSET);


    /**
     *
     *
     * @param builder
     * @param key
     * @param value
     */
    private static void addBody(MultipartEntityBuilder builder, String key, Object value) {
        if (value instanceof List) {
            List<?> values = (List<?>) value;
            for (Object obj : values) {
                addBody(builder, key, obj);
            }
        } else if (value instanceof byte[]) {
            builder.addBinaryBody(key, (byte[]) value);
        } else if (value instanceof File) {
            builder.addBinaryBody(key, (File) value);
        } else if (value instanceof String[]) {
            String[] psStrings = (String[]) value;
            key += "[]";
            for (String v : psStrings) {
                builder.addTextBody(key, v);
            }
        } else {
            builder.addTextBody(key, value.toString());
        }
    }

    /**
     * 提交二进制请求
     *
     * @param url
     * @param params
     * @return
     * @throws IOException
     * @throws ParseException
     */
    public static HttpClientResult doBinaryPost(String url, Map<String, Object> params) {
        // System.out.println("url: " + url);
        HttpClientResult result = null;
        try {
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            if (params != null && params.size() > 0) {
                Object value = null;
                for (String key : params.keySet()) {
                    value = params.get(key);
                    addBody(builder, key, value);
                }
            }
            HttpEntity entity = builder.build();
            httpPost.setEntity(entity);
            CloseableHttpResponse response1 = httpclient.execute(httpPost);
            if (entity != null) {
                result = new HttpClientResult();
                result.setStatus(response1.getStatusLine().getStatusCode());
                HttpEntity entity1 = response1.getEntity();
                String returnStr = EntityUtils.toString(entity1);
                EntityUtils.consume(entity1);
                result.setData(returnStr);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 提交二进制请求
     *
     * @param url
     * @param params
     * @return
     * @throws IOException
     * @throws ParseException
     */
    public static HttpClientResult doBinaryPost(String url, Map<String, Object> params, String tempFile)
            throws Exception {
        HttpClientResult result = null;
        try {
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            if (params != null && params.size() > 0) {
                Object value = null;
                for (String key : params.keySet()) {
                    value = params.get(key);
                    if (value instanceof byte[]) {
                        builder.addBinaryBody(key, (byte[]) value, ContentType.DEFAULT_BINARY, tempFile);
                    } else {
                        builder.addTextBody(key, value.toString(), ContentType.TEXT_PLAIN);
                    }
                }
            }
            HttpEntity entity = builder.build();
            httpPost.setEntity(entity);
            CloseableHttpResponse response1 = httpclient.execute(httpPost);
            if (entity != null) {
                result = new HttpClientResult();
                result.setStatus(response1.getStatusLine().getStatusCode());
                HttpEntity entity1 = response1.getEntity();
                String returnStr = EntityUtils.toString(entity1);
                EntityUtils.consume(entity1);
                result.setData(returnStr);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get调用
     *
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public static HttpClientResult doGet(String url, Map<String, String> params) throws Exception {
        return doGet(url, params, CONTENT_CHARSET);
    }

    /**
     * get调用
     *
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public static HttpClientResult doGet(String url, Map<String, String> params, String charset) throws Exception {
        HttpClientResult result = null;
        try {
            HttpClient client = buildHttpClient(false);
            HttpGet get = buildHttpGet(url, params);
            HttpResponse response = client.execute(get);
            // assertStatus(response);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = new HttpClientResult();
                result.setStatus(response.getStatusLine().getStatusCode());
                result.setData(EntityUtils.toString(entity, charset));
                EntityUtils.consume(entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * post调用
     *
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static HttpClientResult doPostFormData(String url, Map<String, String> params) {
        return doPostFormData(url, params, CONTENT_CHARSET);
    }

    /**
     * 简单post调用
     *
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static HttpClientResult doPostFormData(String url, Map<String, String> params, String charset) {
        HttpClientResult result = null;
        try {
            HttpClient client = buildHttpClient(false);
            HttpPost postMethod = buildHttpPost(url, params);
            HttpResponse response = client.execute(postMethod);
            // assertStatus(response);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = new HttpClientResult();
                result.setStatus(response.getStatusLine().getStatusCode());
                result.setData(EntityUtils.toString(entity, charset));
                EntityUtils.consume(entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 创建HttpClient
     *
     * @param isMultiThread
     * @return
     */
    public static HttpClient buildHttpClient(boolean isMultiThread) {
        CloseableHttpClient client = null;
        if (isMultiThread) {
            client = HttpClientBuilder.create().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
        } else {
            client = HttpClientBuilder.create().build();
        }
        return client;
    }

    /**
     *
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public static HttpPost buildHttpPost(String url, Map<String, String> params) throws Exception {
        if (StringUtils.isBlank(url)) {
            throw new Exception("url is null.");
        }
        HttpPost post = new HttpPost(url);
        setCommonHttpMethod(post);
        HttpEntity he = null;
        if (params != null) {
            List<NameValuePair> formparams = new ArrayList<NameValuePair>();
            for (String key : params.keySet()) {
                formparams.add(new BasicNameValuePair(key, params.get(key)));
            }
            he = new UrlEncodedFormEntity(formparams, GBK);
            post.setEntity(he);
        }
        return post;

    }

    /**
     *
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public static HttpGet buildHttpGet(String url, Map<String, String> params) throws Exception {
        if (StringUtils.isBlank(url)) {
            throw new Exception("url is null.");
        }
        HttpGet get = new HttpGet(buildGetUrl(url, params));
        return get;
    }

    /**
     * build getUrl str
     *
     * @param url
     * @param params
     * @return
     */
    public static String buildGetUrl(String url, Map<String, String> params) {
        StringBuffer uriStr = new StringBuffer(url);
        if (params != null) {
            List<NameValuePair> ps = new ArrayList<NameValuePair>();
            for (String key : params.keySet()) {
                ps.add(new BasicNameValuePair(key, params.get(key)));
            }
            uriStr.append("?");
            uriStr.append(URLEncodedUtils.format(ps, UTF_8));
        }
        return uriStr.toString();
    }

    /**
     * 设置HttpMethod通用配置
     *
     * @param httpMethod
     */
    public static void setCommonHttpMethod(HttpRequestBase httpMethod) {
        httpMethod.setHeader(HTTP.CONTENT_ENCODING, CONTENT_CHARSET);// setting
    }

    /**
     * body为json的post调用
     *
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static HttpClientResult doPostJson(String url, Map<String, Object> params) throws Exception{
        return doPostJson(url, params, CONTENT_CHARSET);
    }

    /**
     *
     *
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static HttpClientResult doPostJson(String url, Map<String, Object> params, String charset) throws Exception{
        HttpClientResult result = null;
        try {
            HttpClient client = buildHttpClient(false);
            HttpPost postMethod = buildJsonHttpPost(url, params);
            HttpResponse response = client.execute(postMethod);
            // assertStatus(response);
            HttpEntity entity = response.getEntity();

            if (entity != null) {
                result = new HttpClientResult();
                result.setStatus(response.getStatusLine().getStatusCode());
                result.setData(EntityUtils.toString(entity, charset));

                EntityUtils.consume(entity);
            } else {
                throw new NoHttpResponseException("entity null");
            }
        } catch (Exception e) {
            System.out.println(">>>>>>httpclient doPost error: " + e.getMessage());
            e.printStackTrace();
            throw e;
        }
        return result;
    }

    /**
     * 构建httpPost对象
     *
     * @param url
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     * @throws URISyntaxException
     */
    public static HttpPost buildJsonHttpPost(String url, Map<String, Object> params) throws Exception {
        if (StringUtils.isBlank(url)) {
            throw new Exception("url is null.");
        }
        HttpPost post = new HttpPost(url);
        setCommonHttpMethod(post);
        post.setConfig(buildRequestConfig());
        HttpEntity he = null;
        if (params != null) {
            ObjectMapper mapper = new ObjectMapper();
            String s = mapper.writeValueAsString(params);

//            he = new StringEntity(JSON.toJSONString(params));
            he = new StringEntity(s);
            System.out.println(">>>>> http content length: " + he.getContentLength());
            post.setEntity(he);
        }
        // 在RequestContent.process中会自动写入消息体的长度，自己不用写入，写入反而检测报错
        // setContentLength(post, he);
        return post;

    }

    /**
     * 构建公用RequestConfig
     *
     * @return
     */
    public static RequestConfig buildRequestConfig() {
        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SO_TIMEOUT_MS)
                .setConnectTimeout(CONNECTION_TIMEOUT_MS).build();
        return requestConfig;
    }


    public static void main(String[] args) throws Exception {
        System.out.println(doGet("http://www.baidu.com", new HashMap<String, String>()));
    }
}
